{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import jieba\n",
    "import pandas as pd\n",
    "df_technology = pd.read_csv(\"technology_news.csv\", encoding='utf-8')\n",
    "df_technology = df_technology.dropna()\n",
    "\n",
    "df_car = pd.read_csv(\"car_news.csv\", encoding='utf-8')\n",
    "df_car = df_car.dropna()\n",
    "\n",
    "df_entertainment = pd.read_csv(\"entertainment_news.csv\", encoding='utf-8')\n",
    "df_entertainment = df_entertainment.dropna()\n",
    "\n",
    "df_military = pd.read_csv(\"military_news.csv\", encoding='utf-8')\n",
    "df_military = df_military.dropna()\n",
    "\n",
    "df_sports = pd.read_csv(\"sports_news.csv\", encoding='utf-8')\n",
    "df_sports = df_sports.dropna()\n",
    "\n",
    "technology = df_technology.content.values.tolist()[1000:21000]\n",
    "car = df_car.content.values.tolist()[1000:21000]\n",
    "entertainment = df_entertainment.content.values.tolist()[:20000]\n",
    "military = df_military.content.values.tolist()[:20000]\n",
    "sports = df_sports.content.values.tolist()[:20000]\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "停用词"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "stopwords=pd.read_csv(\"stopwords.txt\",index_col=False,quoting=3,sep=\"\\t\",names=['stopword'], encoding='utf-8')\n",
    "stopwords=stopwords['stopword'].values"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "构建数据集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def preprocess_text(content_lines, sentences, category):\n",
    "    for line in content_lines:\n",
    "        try:\n",
    "            segs=jieba.lcut(line)\n",
    "            segs = filter(lambda x:len(x)>1, segs)\n",
    "            segs = filter(lambda x:x not in stopwords, segs)\n",
    "            sentences.append((\" \".join(segs), category))\n",
    "        except Exception as e:\n",
    "            print(line)\n",
    "            continue \n",
    "\n",
    "#生成训练数据\n",
    "sentences = []\n",
    "\n",
    "preprocess_text(technology, sentences, 'technology')\n",
    "preprocess_text(car, sentences, 'car')\n",
    "preprocess_text(entertainment, sentences, 'entertainment')\n",
    "preprocess_text(military, sentences, 'military')\n",
    "preprocess_text(sports, sentences, 'sports')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from sklearn.model_selection import train_test_split\n",
    "x, y = zip(*sentences)\n",
    "train_data, test_data, train_target, test_target = train_test_split(x, y, random_state=1234)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "基于卷积神经网络的中文文本分类\n",
    "\"\"\"\n",
    "\n",
    "from __future__ import absolute_import\n",
    "from __future__ import division\n",
    "from __future__ import print_function\n",
    "\n",
    "import argparse\n",
    "import sys\n",
    "\n",
    "import numpy as np\n",
    "import pandas\n",
    "from sklearn import metrics\n",
    "import tensorflow as tf\n",
    "\n",
    "learn = tf.contrib.learn\n",
    "\n",
    "FLAGS = None\n",
    "\n",
    "#文档最长长度\n",
    "MAX_DOCUMENT_LENGTH = 100\n",
    "#最小词频数\n",
    "MIN_WORD_FREQUENCE = 2\n",
    "#词嵌入的维度\n",
    "EMBEDDING_SIZE = 20\n",
    "#filter个数\n",
    "N_FILTERS = 10\n",
    "#感知野大小\n",
    "WINDOW_SIZE = 20\n",
    "#filter的形状\n",
    "FILTER_SHAPE1 = [WINDOW_SIZE, EMBEDDING_SIZE]\n",
    "FILTER_SHAPE2 = [WINDOW_SIZE, N_FILTERS]\n",
    "#池化\n",
    "POOLING_WINDOW = 4\n",
    "POOLING_STRIDE = 2\n",
    "n_words = 0\n",
    "\n",
    "\n",
    "def cnn_model(features, target):\n",
    "\t\"\"\"\n",
    "    2层的卷积神经网络，用于短文本分类\n",
    "    \"\"\"\n",
    "\t# 先把词转成词嵌入\n",
    "\t# 我们得到一个形状为[n_words, EMBEDDING_SIZE]的词表映射矩阵\n",
    "\t# 接着我们可以把一批文本映射成[batch_size, sequence_length, EMBEDDING_SIZE]的矩阵形式\n",
    "\ttarget = tf.one_hot(target, 15, 1, 0)\n",
    "\tword_vectors = tf.contrib.layers.embed_sequence(\n",
    "\t\t\tfeatures, vocab_size=n_words, embed_dim=EMBEDDING_SIZE, scope='words')\n",
    "\tword_vectors = tf.expand_dims(word_vectors, 3)\n",
    "\twith tf.variable_scope('CNN_Layer1'):\n",
    "\t\t# 添加卷积层做滤波\n",
    "\t\tconv1 = tf.contrib.layers.convolution2d(\n",
    "\t\t\t\tword_vectors, N_FILTERS, FILTER_SHAPE1, padding='VALID')\n",
    "\t\t# 添加RELU非线性\n",
    "\t\tconv1 = tf.nn.relu(conv1)\n",
    "\t\t# 最大池化\n",
    "\t\tpool1 = tf.nn.max_pool(\n",
    "\t\t\t\tconv1,\n",
    "\t\t\t\tksize=[1, POOLING_WINDOW, 1, 1],\n",
    "\t\t\t\tstrides=[1, POOLING_STRIDE, 1, 1],\n",
    "\t\t\t\tpadding='SAME')\n",
    "\t\t# 对矩阵进行转置，以满足形状\n",
    "\t\tpool1 = tf.transpose(pool1, [0, 1, 3, 2])\n",
    "\twith tf.variable_scope('CNN_Layer2'):\n",
    "\t\t# 第2个卷积层\n",
    "\t\tconv2 = tf.contrib.layers.convolution2d(\n",
    "\t\t\t\tpool1, N_FILTERS, FILTER_SHAPE2, padding='VALID')\n",
    "\t\t# 抽取特征\n",
    "\t\tpool2 = tf.squeeze(tf.reduce_max(conv2, 1), squeeze_dims=[1])\n",
    "\n",
    "\t# 全连接层\n",
    "\tlogits = tf.contrib.layers.fully_connected(pool2, 15, activation_fn=None)\n",
    "\tloss = tf.losses.softmax_cross_entropy(target, logits)\n",
    "\n",
    "\ttrain_op = tf.contrib.layers.optimize_loss(\n",
    "\t\t\tloss,\n",
    "\t\t\ttf.contrib.framework.get_global_step(),\n",
    "\t\t\toptimizer='Adam',\n",
    "\t\t\tlearning_rate=0.01)\n",
    "\n",
    "\treturn ({\n",
    "\t\t\t'class': tf.argmax(logits, 1),\n",
    "\t\t\t'prob': tf.nn.softmax(logits)\n",
    "\t}, loss, train_op)\n",
    "\n",
    "\n",
    "#构建数据集\n",
    "#x_train = pandas.DataFrame(train_data)[1]\n",
    "#y_train = pandas.Series(train_target)\n",
    "#x_test = pandas.DataFrame(test_data)[1]\n",
    "#y_test = pandas.Series(test_target)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "来看看sklearn的VocabularyProcessor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[array([1, 2, 0, 0, 0, 0, 0, 0, 0, 0], dtype=int64),\n",
       " array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0], dtype=int64),\n",
       " array([1, 2, 0, 0, 0, 0, 0, 0, 0, 0], dtype=int64),\n",
       " array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0], dtype=int64)]"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tmp = ['I am good', 'you are here', 'I am glad', 'it is great']\n",
    "vocab_processor = learn.preprocessing.VocabularyProcessor(10, min_frequency=1)\n",
    "list(vocab_processor.fit_transform(tmp))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Total words: 50281\n"
     ]
    }
   ],
   "source": [
    "global n_words\n",
    "# 处理词汇\n",
    "vocab_processor = learn.preprocessing.VocabularyProcessor(MAX_DOCUMENT_LENGTH, min_frequency=MIN_WORD_FREQUENCE)\n",
    "x_train = np.array(list(vocab_processor.fit_transform(train_data)))\n",
    "x_test = np.array(list(vocab_processor.transform(test_data)))\n",
    "n_words = len(vocab_processor.vocabulary_)\n",
    "print('Total words: %d' % n_words)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "cate_dic = {'technology':1, 'car':2, 'entertainment':3, 'military':4, 'sports':5}\n",
    "train_target = map(lambda x:cate_dic[x], train_target)\n",
    "test_target = map(lambda x:cate_dic[x], test_target)\n",
    "y_train = pandas.Series(train_target)\n",
    "y_test = pandas.Series(test_target)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "INFO:tensorflow:Using default config.\n",
      "WARNING:tensorflow:Using temporary folder as model directory: C:\\Users\\Administrator\\AppData\\Local\\Temp\\tmp8lompfwv\n",
      "INFO:tensorflow:Using config: {'_keep_checkpoint_every_n_hours': 10000, '_tf_config': gpu_options {\n",
      "  per_process_gpu_memory_fraction: 1\n",
      "}\n",
      ", '_task_id': 0, '_save_checkpoints_steps': None, '_tf_random_seed': None, '_log_step_count_steps': 100, '_model_dir': 'C:\\\\Users\\\\Administrator\\\\AppData\\\\Local\\\\Temp\\\\tmp8lompfwv', '_master': '', '_keep_checkpoint_max': 5, '_evaluation_master': '', '_cluster_spec': <tensorflow.python.training.server_lib.ClusterSpec object at 0x000001C97B372438>, '_session_config': None, '_num_worker_replicas': 0, '_environment': 'local', '_save_checkpoints_secs': 600, '_save_summary_steps': 100, '_num_ps_replicas': 0, '_is_chief': True, '_task_type': None}\n",
      "INFO:tensorflow:Create CheckpointSaverHook.\n",
      "INFO:tensorflow:Saving checkpoints for 1 into C:\\Users\\Administrator\\AppData\\Local\\Temp\\tmp8lompfwv\\model.ckpt.\n",
      "INFO:tensorflow:step = 1, loss = 2.70875\n",
      "INFO:tensorflow:global_step/sec: 10.1989\n",
      "INFO:tensorflow:step = 101, loss = 0.7312 (9.811 sec)\n",
      "INFO:tensorflow:global_step/sec: 6.82667\n",
      "INFO:tensorflow:step = 201, loss = 0.518255 (14.652 sec)\n",
      "INFO:tensorflow:global_step/sec: 6.16654\n",
      "INFO:tensorflow:step = 301, loss = 0.379662 (16.212 sec)\n",
      "INFO:tensorflow:global_step/sec: 6.14678\n",
      "INFO:tensorflow:step = 401, loss = 0.61353 (16.269 sec)\n",
      "INFO:tensorflow:global_step/sec: 5.59114\n",
      "INFO:tensorflow:step = 501, loss = 0.200806 (17.886 sec)\n",
      "INFO:tensorflow:global_step/sec: 5.63042\n",
      "INFO:tensorflow:step = 601, loss = 0.09014 (17.763 sec)\n",
      "INFO:tensorflow:global_step/sec: 6.05372\n",
      "INFO:tensorflow:step = 701, loss = 0.250161 (16.520 sec)\n",
      "INFO:tensorflow:global_step/sec: 6.54583\n",
      "INFO:tensorflow:step = 801, loss = 0.234185 (15.329 sec)\n",
      "INFO:tensorflow:global_step/sec: 6.38604\n",
      "INFO:tensorflow:step = 901, loss = 0.318539 (15.605 sec)\n",
      "INFO:tensorflow:global_step/sec: 5.92874\n",
      "INFO:tensorflow:step = 1001, loss = 0.161877 (16.862 sec)\n",
      "INFO:tensorflow:global_step/sec: 6.33985\n",
      "INFO:tensorflow:step = 1101, loss = 0.174736 (15.776 sec)\n",
      "INFO:tensorflow:global_step/sec: 6.77208\n",
      "INFO:tensorflow:step = 1201, loss = 0.184804 (14.772 sec)\n",
      "INFO:tensorflow:global_step/sec: 7.09923\n",
      "INFO:tensorflow:step = 1301, loss = 0.0738641 (14.085 sec)\n",
      "INFO:tensorflow:global_step/sec: 6.14304\n",
      "INFO:tensorflow:step = 1401, loss = 0.188623 (16.272 sec)\n",
      "INFO:tensorflow:global_step/sec: 8.49373\n",
      "INFO:tensorflow:step = 1501, loss = 0.189572 (11.774 sec)\n",
      "INFO:tensorflow:global_step/sec: 8.87464\n",
      "INFO:tensorflow:step = 1601, loss = 0.0418492 (11.268 sec)\n",
      "INFO:tensorflow:global_step/sec: 10.6081\n",
      "INFO:tensorflow:step = 1701, loss = 0.0933082 (9.467 sec)\n",
      "INFO:tensorflow:global_step/sec: 11.4821\n",
      "INFO:tensorflow:step = 1801, loss = 0.140406 (8.668 sec)\n",
      "INFO:tensorflow:global_step/sec: 10.7786\n",
      "INFO:tensorflow:step = 1901, loss = 0.298404 (9.278 sec)\n",
      "INFO:tensorflow:global_step/sec: 11.6822\n",
      "INFO:tensorflow:step = 2001, loss = 0.159314 (8.561 sec)\n",
      "INFO:tensorflow:global_step/sec: 10.8822\n",
      "INFO:tensorflow:step = 2101, loss = 0.0540104 (9.189 sec)\n",
      "INFO:tensorflow:global_step/sec: 11.4874\n",
      "INFO:tensorflow:step = 2201, loss = 0.0492565 (8.706 sec)\n",
      "INFO:tensorflow:global_step/sec: 10.7174\n",
      "INFO:tensorflow:step = 2301, loss = 0.101772 (9.330 sec)\n",
      "INFO:tensorflow:global_step/sec: 11.0786\n",
      "INFO:tensorflow:step = 2401, loss = 0.044592 (9.026 sec)\n",
      "INFO:tensorflow:global_step/sec: 11.2774\n",
      "INFO:tensorflow:step = 2501, loss = 0.0376311 (8.867 sec)\n",
      "INFO:tensorflow:global_step/sec: 10.9571\n",
      "INFO:tensorflow:step = 2601, loss = 0.038446 (9.128 sec)\n",
      "INFO:tensorflow:global_step/sec: 11.4217\n",
      "INFO:tensorflow:step = 2701, loss = 0.0796396 (8.755 sec)\n",
      "INFO:tensorflow:global_step/sec: 10.6967\n",
      "INFO:tensorflow:step = 2801, loss = 0.0630688 (9.349 sec)\n",
      "INFO:tensorflow:global_step/sec: 11.1702\n",
      "INFO:tensorflow:step = 2901, loss = 0.0687314 (8.951 sec)\n",
      "INFO:tensorflow:global_step/sec: 10.7914\n",
      "INFO:tensorflow:step = 3001, loss = 0.0716454 (9.267 sec)\n",
      "INFO:tensorflow:global_step/sec: 11.3581\n",
      "INFO:tensorflow:step = 3101, loss = 0.0989311 (8.846 sec)\n",
      "INFO:tensorflow:global_step/sec: 11.07\n",
      "INFO:tensorflow:step = 3201, loss = 0.00373208 (8.992 sec)\n",
      "INFO:tensorflow:global_step/sec: 10.9633\n",
      "INFO:tensorflow:step = 3301, loss = 0.0464013 (9.120 sec)\n",
      "INFO:tensorflow:global_step/sec: 11.3806\n",
      "INFO:tensorflow:step = 3401, loss = 0.126916 (8.787 sec)\n",
      "INFO:tensorflow:global_step/sec: 10.7277\n",
      "INFO:tensorflow:step = 3501, loss = 0.0441783 (9.323 sec)\n",
      "INFO:tensorflow:global_step/sec: 11.5886\n",
      "INFO:tensorflow:step = 3601, loss = 0.0941981 (8.628 sec)\n",
      "INFO:tensorflow:global_step/sec: 10.7439\n",
      "INFO:tensorflow:step = 3701, loss = 0.0587442 (9.308 sec)\n",
      "INFO:tensorflow:global_step/sec: 9.45221\n",
      "INFO:tensorflow:step = 3801, loss = 0.0670675 (10.580 sec)\n",
      "INFO:tensorflow:global_step/sec: 9.04679\n",
      "INFO:tensorflow:step = 3901, loss = 0.073905 (11.055 sec)\n",
      "INFO:tensorflow:global_step/sec: 9.92046\n",
      "INFO:tensorflow:step = 4001, loss = 0.169336 (10.079 sec)\n",
      "INFO:tensorflow:global_step/sec: 10.1327\n",
      "INFO:tensorflow:step = 4101, loss = 0.0768312 (9.870 sec)\n",
      "INFO:tensorflow:global_step/sec: 9.39445\n",
      "INFO:tensorflow:step = 4201, loss = 0.0479512 (10.644 sec)\n",
      "INFO:tensorflow:global_step/sec: 5.92623\n",
      "INFO:tensorflow:step = 4301, loss = 0.0718784 (16.913 sec)\n",
      "INFO:tensorflow:global_step/sec: 5.64793\n",
      "INFO:tensorflow:step = 4401, loss = 0.0706387 (17.669 sec)\n",
      "INFO:tensorflow:global_step/sec: 6.23425\n",
      "INFO:tensorflow:step = 4501, loss = 0.0278728 (16.039 sec)\n",
      "INFO:tensorflow:global_step/sec: 8.29904\n",
      "INFO:tensorflow:step = 4601, loss = 0.095527 (12.049 sec)\n",
      "INFO:tensorflow:global_step/sec: 9.08196\n",
      "INFO:tensorflow:step = 4701, loss = 0.0470146 (11.011 sec)\n",
      "INFO:tensorflow:global_step/sec: 9.43614\n",
      "INFO:tensorflow:step = 4801, loss = 0.0216588 (10.599 sec)\n",
      "INFO:tensorflow:global_step/sec: 8.5463\n",
      "INFO:tensorflow:step = 4901, loss = 0.0977599 (11.701 sec)\n",
      "INFO:tensorflow:global_step/sec: 8.80119\n",
      "INFO:tensorflow:step = 5001, loss = 0.054138 (11.362 sec)\n",
      "INFO:tensorflow:Saving checkpoints for 5083 into C:\\Users\\Administrator\\AppData\\Local\\Temp\\tmp8lompfwv\\model.ckpt.\n",
      "INFO:tensorflow:global_step/sec: 8.56068\n",
      "INFO:tensorflow:step = 5101, loss = 0.0628322 (11.681 sec)\n",
      "INFO:tensorflow:global_step/sec: 10.6693\n",
      "INFO:tensorflow:step = 5201, loss = 0.0289803 (9.372 sec)\n",
      "INFO:tensorflow:global_step/sec: 9.91351\n",
      "INFO:tensorflow:step = 5301, loss = 0.0415135 (10.146 sec)\n",
      "INFO:tensorflow:global_step/sec: 10.6545\n",
      "INFO:tensorflow:step = 5401, loss = 0.0300617 (9.328 sec)\n",
      "INFO:tensorflow:global_step/sec: 9.91357\n",
      "INFO:tensorflow:step = 5501, loss = 0.042951 (10.087 sec)\n",
      "INFO:tensorflow:global_step/sec: 10.0785\n",
      "INFO:tensorflow:step = 5601, loss = 0.0882639 (9.923 sec)\n",
      "INFO:tensorflow:global_step/sec: 10.5533\n",
      "INFO:tensorflow:step = 5701, loss = 0.0419409 (9.474 sec)\n",
      "INFO:tensorflow:global_step/sec: 9.87731\n",
      "INFO:tensorflow:step = 5801, loss = 0.0631725 (10.125 sec)\n",
      "INFO:tensorflow:global_step/sec: 10.3714\n",
      "INFO:tensorflow:step = 5901, loss = 0.031822 (9.642 sec)\n",
      "INFO:tensorflow:global_step/sec: 9.84908\n",
      "INFO:tensorflow:step = 6001, loss = 0.207399 (10.152 sec)\n",
      "INFO:tensorflow:global_step/sec: 9.9392\n",
      "INFO:tensorflow:step = 6101, loss = 0.05174 (10.061 sec)\n",
      "INFO:tensorflow:global_step/sec: 10.767\n",
      "INFO:tensorflow:step = 6201, loss = 0.0457845 (9.289 sec)\n",
      "INFO:tensorflow:global_step/sec: 10.267\n",
      "INFO:tensorflow:step = 6301, loss = 0.0370208 (9.740 sec)\n",
      "INFO:tensorflow:global_step/sec: 10.7612\n",
      "INFO:tensorflow:step = 6401, loss = 0.0673444 (9.293 sec)\n",
      "INFO:tensorflow:global_step/sec: 10.2575\n",
      "INFO:tensorflow:step = 6501, loss = 0.0450195 (9.750 sec)\n",
      "INFO:tensorflow:global_step/sec: 8.67006\n",
      "INFO:tensorflow:step = 6601, loss = 0.207612 (11.662 sec)\n",
      "INFO:tensorflow:global_step/sec: 10.4934\n",
      "INFO:tensorflow:step = 6701, loss = 0.0367587 (9.404 sec)\n",
      "INFO:tensorflow:global_step/sec: 9.17198\n",
      "INFO:tensorflow:step = 6801, loss = 0.00382407 (10.899 sec)\n",
      "INFO:tensorflow:global_step/sec: 9.97791\n",
      "INFO:tensorflow:step = 6901, loss = 0.049619 (10.023 sec)\n",
      "INFO:tensorflow:Saving checkpoints for 7000 into C:\\Users\\Administrator\\AppData\\Local\\Temp\\tmp8lompfwv\\model.ckpt.\n",
      "INFO:tensorflow:Loss for final step: 0.0500151.\n",
      "INFO:tensorflow:Restoring parameters from C:\\Users\\Administrator\\AppData\\Local\\Temp\\tmp8lompfwv\\model.ckpt-7000\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy: 0.866067\n"
     ]
    }
   ],
   "source": [
    "# 构建模型\n",
    "classifier = learn.SKCompat(learn.Estimator(model_fn=cnn_model))\n",
    "\n",
    "# 训练和预测\n",
    "classifier.fit(x_train, y_train, steps=7000)\n",
    "y_predicted = classifier.predict(x_test)['class']\n",
    "score = metrics.accuracy_score(y_test, y_predicted)\n",
    "print('Accuracy: {0:f}'.format(score))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
